iT邦幫忙

2025 iThome 鐵人賽

DAY 17
0
生成式 AI

iOS? AI-Yes!:用 Vide Coding 加速我的 Swift 學習曲線系列 第 17

Day 17 - 程式碼健檢:當 MVC 遇上瓶頸,用 MVVM 來拯救你的 ViewController

  • 分享至 

  • xImage
  •  

在過去的十幾天裡,我們透過 Apple 經典的 MVC (Model-View-Controller) 架構,從零到有成功打造了一個功能齊全的鬧鐘 App。這證明了 MVC 作為一個入門框架的價值,它簡單直觀。

然而,當我們完成所有功能,回顧 MainViewController.swift 時,卻發現這個檔案已經變成一個龐然大物。它裡面有 UI 設定、有 UITableView 的代理方法、有 Realm 資料庫的讀寫、有刪除鬧鐘的邏輯、有檢查過期鬧鐘的規則,甚至還有格式化顯示文字的輔助函式。

  • 困惑點:MVC 模式的瓶頸在哪裡?隨著專案功能的堆疊,我親身體驗到了 MVC 在複雜場景下的幾個典型痛點,也就是常說的「Massive View Controller (重量級視圖控制器)」問題

  • AI 協作

    • 我的 Prompt:我的鬧鐘 App 現在功能都完成了,但我覺得 MainViewController 好臃腫,裡面有 UI 設定、有 Realm 資料庫操作、還有各種格式化文字的邏輯,全部混在一起。未來如果想修改或測試都很困難。在 iOS 開發中有沒有更好的架構模式可以解決?請簡單說明並不用給程式碼

    AI 的回答:

    在 iOS 開發中,您遇到的 MainViewController 職責過多,也就是俗稱的「臃腫視圖控制器」(Massive View Controller) 問題,這是一個非常普遍的挑戰。為了解決這個問題,許多架構模式應運而生,它們的共同目標都是將原本集中在 ViewController 的邏輯分散到不同的物件中,以實現關注點分離(Separation of Concerns),讓程式碼更易於維護、測試和擴展。

    以下是幾個常見且能解決您問題的架構模式,我將簡單介紹它們的核心概念:

    MVC (Model-View-Controller)

    MVC 是 Apple 官方推薦的基礎模式,但它也常常是造成您問題的根源。許多開發者誤解了其定義,將所有邏輯塞入 Controller

    • Model (模型):負責處理資料和業務邏輯。例如:您的鬧鐘資料(時間、名稱、是否啟用)、鬧鐘資料的儲存(如 Realm 資料庫操作)。
    • View (視圖):負責使用者介面。例如:顯示鬧鐘列表的 UITableView、按鈕和標籤。
    • Controller (控制器):作為 ModelView 之間的橋樑。它接收使用者在 View 上的操作(如點擊),並更新 Model;同時,當 Model 資料變動時,它也會更新 View 的顯示。

    您目前的問題是 Controller 承擔了太多 Model 的責任(如 Realm 操作)和 View 的責任(如 UI 設定和格式化邏輯)。要解決這個問題,您需要將這些邏輯從 MainViewController 中抽離。

    MVVM (Model-View-ViewModel)

    MVVM 是一個非常流行的模式,它旨在解決傳統 MVC 中 Controller 變得臃腫的問題。

    • Model (模型):與 MVC 中的 Model 相同,處理資料和業務邏輯(例如您的鬧鐘資料和 Realm 操作)。
    • View (視圖):與 MVC 中的 View 相同,只負責顯示使用者介面,並且只包含最少量的 UI 邏輯。
    • ViewModel (視圖模型):這是 MVVM 的核心。它是一個獨立於 View 的物件,負責管理 View 的狀態和邏輯。它會從 Model 取得資料,並將其處理成 View 可以直接顯示的格式。ViewModel 並不知道 View 的存在,View 則會「綁定」(bind) 到 ViewModel 的屬性,當 ViewModel 中的資料改變時,View 會自動更新。

    在您的鬧鐘 App 中,您可以創建一個 AlarmListViewModel。這個 ViewModel 將負責:

    1. Realm 讀取和寫入鬧鐘資料。
    2. 將原始資料格式化成 View 可以直接顯示的字串(如將日期轉換為 HH:mm 格式)。
    3. 處理使用者操作的邏輯,例如點擊啟用/停用鬧鐘。

    MainViewController 只需要持有這個 AlarmListViewModel,並將其屬性綁定到 UI 上即可,如此一來,它將變得非常輕量。

    VIPER (View-Interactor-Presenter-Entity-Router)

    VIPER 是一個更為嚴格和複雜的模式,它將應用程式的各個職責切分得更細,非常適合大型且需要高度可測試性的專案。

    • View (視圖):與 MVVM 的 View 類似,只負責顯示 UI 和將使用者輸入傳給 Presenter
    • Interactor (互動器):包含所有的業務邏輯和資料操作,如與 Realm 的互動。它不關心 UI,只專注於資料層
    • Presenter (展示者):負責從 Interactor 取得資料,將其處理成 View 可以顯示的格式,然後傳給 ViewPresenter 就像是 ControllerViewModel 的角色,但職責更為明確。
    • Entity (實體):代表應用程式的資料模型,例如您的鬧鐘物件。
    • Router (路由):負責處理不同畫面的導航邏輯,如從鬧鐘列表頁跳轉到新增鬧鐘頁面。

    VIPER 的優點在於它的職責劃分非常清晰,每個元件都只做一件事情,這使得單元測試變得非常容易。但相對地,它會讓專案的檔案數量和複雜度大幅增加,對於中小型專案來說,可能有點過度設計。

    針對您的鬧鐘 App,MVVM 會是一個非常好的選擇。它既能有效解決您 MainViewController 臃腫的問題,又能保持相對簡單的架構,並且非常利於日後的單元測試。您只需要將 Realm 的資料操作和文字格式化邏輯移到一個獨立的 ViewModel 類別中,您的 MainViewController 就能大幅瘦身,並專注於 UI 的協調工作。

    如果您對這些架構模式有進一步的疑問,或是想知道如何將您的專案重構成 MVVM,我們可以再深入討論。

AI的總結與建議

架構模式 核心概念 優點 缺點 適合情境
MVC 視圖、模型、控制器 簡單、直觀、Apple 官方推薦 ViewController 易臃腫 小型專案或快速原型開發
MVVM 視圖、視圖模型、模型 輕量化 ViewController、易於測試 存在 ViewModelView綁定關係,需額外處理 中型專案或需要更好測試性時
VIPER 視圖、互動器、展示者、實體、路由 職責劃分最清晰、單元測試最容易 複雜度高、檔案數量多、學習曲線陡峭 大型專案或高度嚴謹的團隊開發

結論與我的選擇

AI 的回答為我打開了一扇新的大門。它不僅清晰地指出了我目前在 MainViewController.swift 中遇到的「Massive View Controller」問題,還一次講解了三種業界主流的解決方案:MVC 的正確實踐、更現代的 MVVM,以及更嚴謹的 VIPER。

對比這三種模式,我有了非常清晰的結論:

  • 堅持 MVC:雖然可以透過更嚴格的職責劃分來優化,但很容易在不經意間又重蹈覆轍,將邏輯加回 Controller。
  • 挑戰 VIPER:對於我們的鬧鐘 App 來說,VIPER 顯然有點「殺雞用牛刀」。為了實現目前的功能而引入五個職責分離的元件,會讓專案變得過於複雜。
  • 擁抱 MVVM:MVVM 似乎達到了完美的平衡。它透過引入 ViewModel 這個新角色,精準地解決了 MVC 的核心痛點——Controller 職責過重。它將資料處理、狀態管理和商業邏輯從 MainViewController 中抽離,使得 Controller 能夠回歸單純的 View 角色。

雖然我們在這個系列中不會真的動手重構鬧鐘APP,但在未來的開發旅程中,MVVM 將是我的首選方案


上一篇
Day 16 - 【鬧鐘實戰 VI】畫龍點睛:串接系統通知與 UX 優化
下一篇
Day 18 - 鑰匙與門戶:獲取你的第一個 AI API 金鑰並學會安全管理
系列文
iOS? AI-Yes!:用 Vide Coding 加速我的 Swift 學習曲線18
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
yulin494
iT邦新手 4 級 ‧ 2025-10-01 14:05:21

期待後續有MVVM的實做教學!

我要留言

立即登入留言